home *** CD-ROM | disk | FTP | other *** search
/ Amiga Tools 1 / Amiga Tools.iso / disk-tools / cd-tools / amicdrom / iso9660.c < prev    next >
C/C++ Source or Header  |  1994-06-06  |  21KB  |  836 lines

  1. /* iso9660.c:
  2.  *
  3.  * Support for the ISO-9660 filing system.
  4.  *
  5.  * ----------------------------------------------------------------------
  6.  * This code is (C) Copyright 1993,1994 by Frank Munkert.
  7.  * All rights reserved.
  8.  * This software may be freely distributed and redistributed for
  9.  * non-commercial purposes, provided this notice is included.
  10.  * ----------------------------------------------------------------------
  11.  * History:
  12.  * 
  13.  * 25-Apr-94   fmu   The extented attribute record length has to be
  14.  *                   considered when reading file sections.
  15.  * 17-Feb-94   fmu   Volume ID must not be longer than 30 characters.
  16.  * 05-Feb-94   fmu   Added support for relocated directories.
  17.  * 07-Jan-94   fmu   Support for drives which don't support the SCSI-2
  18.  *                   READ TOC command.
  19.  * 01-Jan-94   fmu   Added multisession support.
  20.  * 11-Dec-93   fmu   Fixed bug in Iso_Find_Parent().
  21.  * 02-Dec-93   fmu   Bugfix: a logical block of a file extent must not
  22.  *                   necessarily start at a logical sector border.
  23.  * 29-Nov-93   fmu   - New function Iso_Block_Size().
  24.  *                   - Support for variable logical block sizes.
  25.  * 15-Nov-93   fmu   Uses_High_Sierra_Protocol added.
  26.  * 13-Nov-93   fmu   Bad iso_errno return value in Iso_Open_Obj_In_Directory
  27.  *                   corrected.
  28.  * 12-Oct-93   fmu   Adapted to new VOLUME and CDROM_OBJ structures.
  29.  * 24-Sep-93   fmu   Two further bugs in Seek_Position fixed.
  30.  * 16-Sep-93   fmu   Fixed bug in Seek_Position.
  31.  * 16-Sep-93   fmu   Bugfix: Top level object recognition in CDROM_Info
  32.  *                   had to be changed for Rock Ridge disks.
  33.  */
  34.  
  35. #include <stdlib.h>
  36. #include <string.h>
  37. #include <ctype.h>
  38.  
  39. #include <exec/types.h>
  40. #include <exec/memory.h>
  41. #include <clib/exec_protos.h>
  42. #include <clib/utility_protos.h>
  43. #ifdef AZTEC_C
  44. #include <pragmas/exec_lib.h>
  45. #include <pragmas/utility_lib.h>
  46. #endif
  47. #ifdef LATTICE
  48. #include <pragmas/exec_pragmas.h>
  49. #include <pragmas/utility_pragmas.h>
  50. #endif
  51. #if defined(_DCC) && defined(REGISTERED)
  52. #include <pragmas/exec_pragmas.h>
  53. #include <pragmas/utility_pragmas.h>
  54. extern struct Library *SysBase;
  55. #endif
  56.  
  57. #include "cdrom.h"
  58. #include "iso9660.h"
  59. #include "rock.h"
  60.  
  61. extern struct Library *UtilityBase;
  62.  
  63. t_bool Iso_Is_Top_Level_Object (CDROM_OBJ *);
  64.  
  65. int iso_errno;
  66.  
  67. #define VOL(vol,tag) (((t_iso_vol_info *)(vol->vol_info))->tag)
  68. #define OBJ(obj,tag) (((t_iso_obj_info *)(obj->obj_info))->tag)
  69.  
  70. /* Check whether the given volume uses the ISO 9660 Protocol.
  71.  * The protocol is identified by the sequence
  72.  *            'C' 'D' '0' '0' '1'
  73.  * in the 2nd..6th byte of sector 16 of a track.
  74.  *
  75.  * All data tracks on the disk are examined.
  76.  *
  77.  * Returns TRUE iff the ISO protocol is used; FALSE otherwise.
  78.  */
  79.  
  80. t_bool Uses_Iso_Protocol (CDROM *p_cdrom, t_ulong *p_offset)
  81. {
  82.   int i, len;
  83.   t_ulong *buf;
  84.  
  85.   /* If Data_Tracks() returns -1, then the drive probably doesn't support
  86.    * the SCSI-2 READ TOC command.
  87.    */
  88.   if (p_cdrom->use_trackdisk ||
  89.       (len = Data_Tracks (p_cdrom, &buf)) < 0) {
  90.     *p_offset = 0;
  91.     if (!Read_Sector (p_cdrom, 16))
  92.       return FALSE;  
  93.     return strncmp ((char *) p_cdrom->buffer + 1, "CD001", 5) == 0;
  94.   }
  95.  
  96.   if (len == 0)
  97.     return FALSE;
  98.  
  99.   for (i=len-1; i>=0; i--) {
  100.     *p_offset = buf[i];
  101.     if (!Read_Sector (p_cdrom, 16 + *p_offset))
  102.       continue;
  103.     if (strncmp ((char *) p_cdrom->buffer + 1, "CD001", 5) == 0) {
  104.       FreeVec (buf);
  105.       return TRUE;
  106.     }
  107.   }
  108.  
  109.   FreeVec (buf);
  110.   return FALSE;
  111. }
  112.  
  113. /* Check whether the given volume uses the High Sierra Protocol.
  114.  * The protocol is identified by the sequence
  115.  *            'C' 'D' 'R' 'O' 'M'
  116.  * in the 10th..14th byte of sector 16.
  117.  *
  118.  * Returns TRUE iff the High Sierra protocol is used; FALSE otherwise.
  119.  */
  120.  
  121. t_bool Uses_High_Sierra_Protocol (CDROM *p_cdrom)
  122. {
  123.   if (!Read_Sector (p_cdrom, 16))
  124.     return FALSE;
  125.   
  126.   return strncmp ((char *) p_cdrom->buffer + 9, "CDROM", 5) == 0;
  127. }
  128.  
  129. t_bool Iso_Init_Vol_Info (VOLUME *p_volume, int p_skip, t_ulong p_offset)
  130. {
  131.   long loc = 16 + p_offset;
  132.   extern t_handler g_iso_handler, g_rr_handler;
  133.  
  134.   if (p_volume->protocol == PRO_ISO)
  135.     p_volume->handler = &g_iso_handler;
  136.   else
  137.     p_volume->handler = &g_rr_handler;
  138.  
  139.   p_volume->vol_info = AllocMem (sizeof (t_iso_vol_info), MEMF_PUBLIC);
  140.   if (!p_volume->vol_info) {
  141.     iso_errno = ISOERR_NO_MEMORY;
  142.     return FALSE;
  143.   }
  144.  
  145.   for (;;) {
  146.     if (!Read_Sector (p_volume->cd, loc)) {
  147.       iso_errno = ISOERR_SCSI_ERROR;
  148.       FreeMem (p_volume->vol_info, sizeof (t_iso_vol_info));
  149.       return FALSE;
  150.     }
  151.  
  152.     if (p_volume->cd->buffer[0] == 1) {
  153.       memcpy (&VOL(p_volume,pvd), p_volume->cd->buffer, sizeof (prim_vol_desc));
  154.       break;
  155.     }
  156.     
  157.     if (p_volume->cd->buffer[0] == 255 || loc > 1000) {
  158.       iso_errno = ISOERR_NO_PVD;
  159.       FreeMem (p_volume->vol_info, sizeof (t_iso_vol_info));
  160.       return FALSE;
  161.     }
  162.     
  163.     loc++;
  164.   }
  165.   
  166.   VOL(p_volume,skip) = p_skip;
  167.  
  168.   switch (VOL(p_volume,pvd).block_size_m) {
  169.   case 512:
  170.     VOL(p_volume,blockshift) = 2;
  171.     break;
  172.   case 1024:
  173.     VOL(p_volume,blockshift) = 1;
  174.     break;
  175.   case 2048:
  176.   default:
  177.     VOL(p_volume,blockshift) = 0;
  178.     break;
  179.   }
  180.  
  181.   return TRUE;
  182. }
  183.  
  184. void Iso_Close_Vol_Info (VOLUME *p_volume)
  185. {
  186.   FreeMem (p_volume->vol_info, sizeof (t_iso_vol_info));
  187. }
  188.  
  189. CDROM_OBJ *Iso_Alloc_Obj (int p_length_of_dir_record)
  190. {
  191.   CDROM_OBJ *obj;
  192.  
  193.   obj = AllocMem (sizeof (CDROM_OBJ), MEMF_PUBLIC | MEMF_CLEAR);
  194.   if (!obj) {
  195.     iso_errno = ISOERR_NO_MEMORY;
  196.     return NULL;
  197.   }
  198.  
  199.   obj->obj_info = AllocMem (sizeof (t_iso_obj_info), MEMF_PUBLIC);
  200.   if (!obj->obj_info) {
  201.     FreeMem (obj, sizeof (CDROM_OBJ));
  202.     return NULL;
  203.   }
  204.  
  205.   OBJ(obj,dir) = AllocMem (p_length_of_dir_record, MEMF_PUBLIC);
  206.   if (!OBJ(obj,dir)) {
  207.     iso_errno = ISOERR_NO_MEMORY;
  208.     FreeMem (obj->obj_info, sizeof (t_iso_obj_info));
  209.     FreeMem (obj, sizeof (CDROM_OBJ));
  210.     return NULL;
  211.   }
  212.  
  213.   return obj;
  214. }
  215.  
  216. /* Get the "CDROM object" for the root directory of the volume.
  217.  */
  218.  
  219. CDROM_OBJ *Iso_Open_Top_Level_Directory (VOLUME *p_volume)
  220. {
  221.   CDROM_OBJ *obj;
  222.  
  223.   obj = Iso_Alloc_Obj (VOL(p_volume,pvd).root.length);
  224.   if (!obj)
  225.     return NULL;
  226.  
  227.   obj->directory_f = TRUE;
  228.   obj->volume = p_volume;
  229.   obj->pos = 0;
  230.   memcpy (OBJ(obj,dir), &VOL(p_volume,pvd).root, VOL(p_volume,pvd).root.length);
  231.  
  232.   return obj;
  233. }
  234.  
  235. /* Test on equality of directory names (ignoring case).
  236.  */
  237.  
  238. int Directory_Names_Equal (char *p_iso_name, int p_length, char *p_name)
  239. {
  240.   return Strncasecmp (p_iso_name, p_name, p_length) == 0 &&
  241.        p_name[p_length] == 0;
  242. }
  243.  
  244. /* Compare the name of the directory entry p_iso_name (with length p_length)
  245.  * with the C string p_name, and return 1 iff both strings are equal.
  246.  * NOTE: p_iso_name may be a file name (with version number) or a directory
  247.  *       name (without version number).
  248.  */
  249.  
  250. int Names_Equal (char *p_iso_name, int p_length, char *p_name)
  251. {
  252.   int pos;
  253.  
  254.   if (Strncasecmp (p_iso_name, p_name, p_length) == 0 &&
  255.       p_name[p_length] == 0)
  256.     return TRUE;
  257.   
  258.   /* compare without version number: */
  259.   
  260.   for (pos=p_length-1; pos>=0; pos--)
  261.     if (p_iso_name[pos] == ';')
  262.       break;
  263.  
  264.   if (pos>=0)
  265.     return (Strncasecmp (p_iso_name, p_name, pos) == 0 &&
  266.             p_name[pos] == 0);
  267.   else
  268.     return FALSE;
  269. }
  270.  
  271. /* Get a record from a directory.
  272.  * p_location is a LOGICAL BLOCK number.
  273.  */
  274.  
  275. directory_record *Get_Directory_Record (VOLUME *p_volume,
  276.                     unsigned long p_location,
  277.                     unsigned long p_offset)
  278. {
  279.   static unsigned char result[256];
  280.   int len;
  281.   int loc;
  282.   
  283.   loc = (p_location >> VOL(p_volume,blockshift)) + (p_offset >> 11);
  284.   if (!Read_Sector (p_volume->cd, loc)) {
  285.     iso_errno = ISOERR_SCSI_ERROR;
  286.     return NULL;
  287.   }
  288.  
  289.   len = p_volume->cd->buffer[p_offset & 2047];
  290.   if (len)
  291.     memcpy (result, p_volume->cd->buffer + (p_offset & 2047), len);
  292.   else
  293.     result[0] = 0;  /* mark as last record */
  294.   
  295.   return (directory_record *) result;
  296. }
  297.  
  298. /* Create a "CDROM object" for the directory which is located
  299.  * at sector p_location.
  300.  */
  301.  
  302. CDROM_OBJ *Iso_Create_Directory_Obj (VOLUME *p_volume, unsigned long p_location)
  303. {
  304.   directory_record *dir;
  305.   unsigned long loc;
  306.   int offset = 0;
  307.   CDROM_OBJ *obj;
  308.   unsigned long len;
  309.  
  310.   if (p_location == VOL(p_volume,pvd).root.extent_loc_m)
  311.     return Iso_Open_Top_Level_Directory (p_volume);
  312.  
  313.   dir = Get_Directory_Record (p_volume, p_location, 0);
  314.   if (!dir)
  315.     return NULL;
  316.   
  317.   dir = Get_Directory_Record (p_volume, p_location, dir->length);
  318.   if (!dir)
  319.     return NULL;
  320.   
  321.   loc = dir->extent_loc_m;
  322.   len = dir->data_length_m;
  323.   for (;;) {
  324.     if (offset >= len)
  325.       return NULL;
  326.     dir = Get_Directory_Record (p_volume, loc, offset);
  327.     if (!dir)
  328.       return NULL;
  329.     if (!dir->length) {
  330.       /* go to next logical sector: */
  331.       offset = (offset & 0xfffff800) + 2048;
  332.       continue;
  333.     }
  334.     if (dir->extent_loc_m == p_location)
  335.       break;
  336.     offset += dir->length;
  337.   }
  338.  
  339.   obj = Iso_Alloc_Obj (dir->length);
  340.   if (!obj)
  341.     return NULL;
  342.  
  343.   obj->directory_f = TRUE;
  344.   obj->volume = p_volume;
  345.   obj->pos = 0;
  346.   memcpy (OBJ(obj,dir), dir, dir->length);
  347.  
  348.   return obj;
  349. }
  350.  
  351.  
  352. /* Open the object with name p_name in the directory p_dir.
  353.  * p_name must not contain '/' or ':' characters.
  354.  */
  355.  
  356. CDROM_OBJ *Iso_Open_Obj_In_Directory (CDROM_OBJ *p_dir, char *p_name)
  357. {
  358.   unsigned long loc = OBJ(p_dir,dir)->extent_loc_m + OBJ(p_dir,dir)->ext_attr_length;
  359.   unsigned long len = OBJ(p_dir,dir)->data_length_m;
  360.   directory_record *dir;
  361.   int offset;
  362.   CDROM_OBJ *obj;
  363.   long cl;
  364.  
  365.   /* skip first two entries: */
  366.  
  367.   dir = Get_Directory_Record (p_dir->volume, loc, 0);
  368.   if (!dir)
  369.     return NULL;
  370.   
  371.   offset = dir->length;
  372.   dir = Get_Directory_Record (p_dir->volume, loc, offset);
  373.   if (!dir)
  374.     return NULL;
  375.  
  376.   offset += dir->length;
  377.   for (;;) {
  378.     if (offset >= len) {
  379.       iso_errno = ISOERR_NOT_FOUND;
  380.       return NULL;
  381.     }
  382.     dir = Get_Directory_Record (p_dir->volume, loc, offset);
  383.     if (!dir)
  384.       return NULL;
  385.     if (!dir->length) {
  386.       /* go to next logical sector: */
  387.       offset = (offset & 0xfffff800) + 2048;
  388.       continue;
  389.     }
  390.     if (p_dir->volume->protocol == PRO_ROCK) {
  391.       char buf[256];
  392.       int len;
  393.  
  394.       if ((len = Get_RR_File_Name (p_dir->volume, dir, buf, sizeof (buf))) > 0 &&
  395.           Strncasecmp (buf, p_name, len) == 0 &&
  396.       p_name[len] == 0)
  397.     break;
  398.     }
  399.  
  400.     if (Names_Equal (dir->file_id, dir->file_id_length, p_name))
  401.       break;
  402.     offset += dir->length;
  403.   }
  404.  
  405.   if (p_dir->volume->protocol == PRO_ROCK &&
  406.       (cl = RR_Child_Link (p_dir->volume, dir)) >= 0)
  407.     return Iso_Create_Directory_Obj (p_dir->volume, cl);
  408.  
  409.   obj = Iso_Alloc_Obj (dir->length);
  410.   if (!obj)
  411.     return NULL;
  412.  
  413.   obj->directory_f = (dir->flags & 2);
  414.   if (p_dir->volume->protocol == PRO_ROCK &&
  415.       Is_A_Symbolic_Link (p_dir->volume, dir)) {
  416.     obj->symlink_f = 1;
  417.     obj->directory_f = 0;
  418.   }
  419.   memcpy (OBJ(obj,dir), dir, dir->length);
  420.   obj->volume = p_dir->volume;
  421.   obj->pos = 0;
  422.   if (!obj->directory_f)
  423.     OBJ(obj,parent_loc) = loc;
  424.  
  425.   return obj;
  426. }
  427.  
  428. /* Close a "CDROM object" and deallocate all associated resources.
  429.  */
  430.  
  431. void Iso_Close_Obj (CDROM_OBJ *p_object)
  432. {
  433.   FreeMem (OBJ(p_object,dir), OBJ(p_object,dir)->length);
  434.   FreeMem (p_object->obj_info, sizeof (t_iso_obj_info));
  435.   FreeMem (p_object, sizeof (CDROM_OBJ));
  436. }
  437.  
  438. /* Read bytes from a file.
  439.  */
  440.  
  441. int Iso_Read_From_File (CDROM_OBJ *p_file, char *p_buffer, int p_buffer_length)
  442. {
  443.   unsigned long loc;
  444.   int remain_block, remain_file, remain;
  445.   int len;
  446.   VOLUME *vol = p_file->volume;
  447.   CDROM *cd = vol->cd;
  448.   int buf_pos = 0;
  449.   int todo;
  450.   unsigned long last_loc, ext_loc;
  451.   short blockshift;
  452.   int offset;
  453.   unsigned long firstblock;
  454.  
  455.   if (p_file->pos == OBJ(p_file,dir)->data_length_m)
  456.     /* at end of file: */
  457.     return 0;
  458.  
  459.   blockshift = VOL(vol,blockshift);
  460.   /* 'firstblock' is the first logical block of the file section: */
  461.   firstblock = OBJ(p_file,dir)->extent_loc_m + OBJ(p_file,dir)->ext_attr_length;
  462.   /*
  463.    * 'offset' is the offset of the first logical block of the file
  464.    * extent from the first logical (2048-byte-)sector.
  465.    */
  466.   if (blockshift)
  467.     offset = ((firstblock & ((1<<blockshift)-1))
  468.               << (11-blockshift));
  469.   else
  470.     offset = 0;
  471.   /*
  472.    * 'ext_loc' is the first logical sector of the file extent.
  473.    * 'loc' is the first logical sector to be read.
  474.    * 'last_loc' is the last logical sector of the file extent.
  475.    */
  476.   ext_loc = firstblock >> blockshift;
  477.   loc = ext_loc + ((p_file->pos + offset) >> 11);
  478.   last_loc = ext_loc + ((OBJ(p_file,dir)->data_length_m + offset - 1) >> 11);
  479.   todo = p_buffer_length;
  480.  
  481.   offset += p_file->pos;
  482.   offset &= 2047;
  483.   remain_block = 2048 - offset;
  484.  
  485.   while (todo) {
  486.     if (!Read_Contiguous_Sectors (cd, loc, last_loc)) {
  487.       iso_errno = ISOERR_SCSI_ERROR;
  488.       return -1;
  489.     }
  490.  
  491.     remain_file = OBJ(p_file,dir)->data_length_m - p_file->pos;
  492.     /* 
  493.      * 'todo' is the number of bytes in p_buffer which haven't been filled yet.
  494.      * 'remain' is remaining number of bytes in cd->buffer.
  495.      */
  496.     remain = (remain_block < remain_file) ? remain_block : remain_file;
  497.     len = (todo < remain) ? todo : remain;
  498.     CopyMem ((APTR) (cd->buffer + offset), (APTR) (p_buffer + buf_pos), len);
  499.     buf_pos += len;
  500.     p_file->pos += len;
  501.     todo -= len;
  502.  
  503.     if (p_file->pos >= OBJ(p_file,dir)->data_length_m)
  504.       break;
  505.  
  506.     remain_block = 2048;
  507.     offset = 0;
  508.  
  509.     loc++;
  510.   }
  511.  
  512.   return buf_pos;
  513. }
  514.  
  515. t_ulong Extract_Date (directory_record *p_dir_record)
  516. {
  517.   struct ClockData ClockData;
  518.  
  519.   ClockData.sec   = p_dir_record->second;
  520.   ClockData.min      = p_dir_record->minute;
  521.   ClockData.hour  = p_dir_record->hour;
  522.   ClockData.mday  = p_dir_record->day;
  523.   ClockData.wday  = 0; /* is ignored by CheckDate() and Date2Amiga() */
  524.   ClockData.month = p_dir_record->month;
  525.   ClockData.year  = p_dir_record->year + 1900;
  526.  
  527.   if (CheckDate (&ClockData))
  528.     return Date2Amiga (&ClockData);
  529.   else
  530.     return 0;
  531. }
  532.  
  533. /* Return information on a "CDROM object."
  534.  */
  535.  
  536. int Iso_CDROM_Info (CDROM_OBJ *p_obj, CDROM_INFO *p_info)
  537. {
  538.   int len;
  539.  
  540.   if (Iso_Is_Top_Level_Object (p_obj)) {
  541.     p_info->name_length = 1;
  542.     p_info->name[0] = ':';
  543.     p_info->directory_f = TRUE;
  544.     p_info->file_length = 0;
  545.     p_info->date = Volume_Creation_Date (p_obj->volume);
  546.   } else {
  547.     if (p_obj->volume->protocol == PRO_ROCK &&
  548.         (len = Get_RR_File_Name (p_obj->volume, OBJ(p_obj,dir),
  549.                        p_info->name, sizeof (p_info->name))) > 0) {
  550.       p_info->name_length = len;
  551.     } else {
  552.       p_info->name_length = OBJ(p_obj,dir)->file_id_length;
  553.       memcpy (p_info->name, OBJ(p_obj,dir)->file_id, p_info->name_length);
  554.     }
  555.     p_info->directory_f = p_obj->directory_f;
  556.     p_info->symlink_f = p_obj->symlink_f;
  557.     p_info->file_length = OBJ(p_obj,dir)->data_length_m;
  558.     p_info->date = Extract_Date (OBJ(p_obj,dir));
  559.   }
  560.  
  561.   return 1;
  562. }
  563.  
  564. /* Browse all entries in a directory.
  565.  */
  566.  
  567. int Iso_Examine_Next (CDROM_OBJ *p_dir, CDROM_INFO *p_info,
  568.               unsigned long *p_offset)
  569. {
  570.   unsigned long offset;
  571.   directory_record *rec;
  572.   int len;
  573.  
  574.   if (!p_dir->directory_f || p_dir->symlink_f) {
  575.     iso_errno = ISOERR_BAD_ARGUMENTS;
  576.     return 0;
  577.   }
  578.  
  579.   if (*p_offset == 0) {
  580.     /* skip first two directory entries: */
  581.   
  582.     rec = Get_Directory_Record
  583.       (p_dir->volume,
  584.        OBJ(p_dir,dir)->extent_loc_m + OBJ(p_dir,dir)->ext_attr_length,
  585.        0);
  586.     if (!rec)
  587.       return 0;
  588.   
  589.     offset = rec->length;
  590.   
  591.     rec = Get_Directory_Record
  592.       (p_dir->volume,
  593.        OBJ(p_dir,dir)->extent_loc_m + OBJ(p_dir,dir)->ext_attr_length,
  594.        offset);
  595.     if (!rec)
  596.       return 0;
  597.   
  598.     *p_offset = offset + rec->length;
  599.   }
  600.  
  601.   for (;;) {
  602.     if (OBJ(p_dir,dir)->data_length_m <= *p_offset)
  603.       return 0;
  604.  
  605.     rec = Get_Directory_Record
  606.         (p_dir->volume,
  607.        OBJ(p_dir,dir)->extent_loc_m + OBJ(p_dir,dir)->ext_attr_length,
  608.      *p_offset);
  609.     if (!rec)
  610.       return 0;
  611.   
  612.     if (rec->length == 0)
  613.       /* go to next logical sector: */
  614.       *p_offset = (*p_offset & 0xfffff800) + 2048;
  615.     else
  616.       break;
  617.   }
  618.  
  619.   *p_offset += rec->length;
  620.  
  621.   if (p_dir->volume->protocol == PRO_ROCK &&
  622.       (len = Get_RR_File_Name (p_dir->volume, rec,
  623.                          p_info->name, sizeof (p_info->name))) > 0) {
  624.       p_info->name_length = len;
  625.   } else {
  626.     p_info->name_length = rec->file_id_length;
  627.     memcpy (p_info->name, rec->file_id, rec->file_id_length);
  628.   }
  629.   if (p_dir->volume->protocol == PRO_ROCK &&
  630.       Is_A_Symbolic_Link (p_dir->volume, rec)) {
  631.     p_info->symlink_f = 1;
  632.     p_info->directory_f = 0;
  633.   } else if (p_dir->volume->protocol == PRO_ROCK &&
  634.              Has_System_Use_Field (p_dir->volume, rec, "CL")) {
  635.     p_info->symlink_f = 0;
  636.     p_info->directory_f = 1;
  637.   } else {
  638.     p_info->symlink_f = 0;
  639.     p_info->directory_f = rec->flags & 2;
  640.   }
  641.   p_info->file_length = rec->data_length_m;
  642.   p_info->date = Extract_Date (rec);
  643.   p_info->suppl_info = rec;
  644.  
  645.   return 1;
  646. }
  647.  
  648. /* Clone a "CDROM object info."
  649.  */
  650.  
  651. void *Iso_Clone_Obj_Info (void *p_info)
  652. {
  653.   t_iso_obj_info *info = (t_iso_obj_info *) p_info;
  654.   t_iso_obj_info *new;
  655.   
  656.   new = AllocMem (sizeof (t_iso_obj_info), MEMF_PUBLIC);
  657.   if (!new)
  658.     return NULL;
  659.  
  660.   memcpy (new, info, sizeof (t_iso_obj_info));
  661.  
  662.   new->dir = AllocMem (info->dir->length, MEMF_PUBLIC);
  663.   if (!new->dir) {
  664.     FreeMem (new, sizeof (t_iso_obj_info));
  665.     return NULL;
  666.   }
  667.   memcpy (new->dir, info->dir, info->dir->length);
  668.  
  669.   return new;
  670. }
  671.  
  672. /* Find parent directory.
  673.  */
  674.  
  675. CDROM_OBJ *Iso_Find_Parent (CDROM_OBJ *p_object)
  676. {
  677.   directory_record *dir;
  678.   unsigned long dir_loc;
  679.   long pl;
  680.  
  681.   if (p_object->directory_f)
  682.     dir_loc = OBJ(p_object,dir)->extent_loc_m + OBJ(p_object,dir)->ext_attr_length;
  683.   else
  684.     dir_loc = OBJ(p_object,parent_loc);
  685.  
  686.   dir = Get_Directory_Record (p_object->volume, dir_loc, 0);
  687.   if (!dir)
  688.     return NULL;
  689.   
  690.   if (p_object->directory_f) {
  691.     dir = Get_Directory_Record (p_object->volume, dir_loc, dir->length);
  692.     if (!dir)
  693.       return NULL;
  694.     if (p_object->volume->protocol == PRO_ROCK &&
  695.         (pl = RR_Parent_Link (p_object->volume, dir)) >= 0)
  696.       return Iso_Create_Directory_Obj (p_object->volume, pl);
  697.   }
  698.  
  699.   return Iso_Create_Directory_Obj (p_object->volume, dir->extent_loc_m);
  700. }
  701.  
  702. /* Test if p_object is the root directory.
  703.  */
  704.  
  705. t_bool Iso_Is_Top_Level_Object (CDROM_OBJ *p_object)
  706. {
  707.   return p_object->directory_f &&
  708.          OBJ(p_object,dir)->extent_loc_m ==
  709.      VOL(p_object->volume,pvd).root.extent_loc_m;
  710. }
  711.  
  712. /* Test if two objects are equal.
  713.  */
  714.  
  715. t_bool Iso_Same_Objects (CDROM_OBJ *p_obj1, CDROM_OBJ *p_obj2)
  716. {
  717.   return (OBJ(p_obj1,dir)->extent_loc_m ==
  718.       OBJ(p_obj2,dir)->extent_loc_m);
  719. }
  720.  
  721. /*
  722.  * Convert p_num digits into an integer value:
  723.  */
  724.  
  725. int Digs_To_Int (char *p_digits, int p_num)
  726. {
  727.   int result = 0;
  728.   int i;
  729.   
  730.   for (i=0; i<p_num; i++)
  731.     result = result * 10 + p_digits[i] - '0';
  732.     
  733.   return result;
  734. }
  735.  
  736. /*
  737.  * Return volume creation date as number of seconds since 1-Jan-1978:
  738.  */
  739.  
  740. t_ulong Iso_Creation_Date (VOLUME *p_volume)
  741. {
  742.   struct ClockData ClockData;
  743.   char *dt = VOL(p_volume,pvd).vol_creation;
  744.  
  745.   ClockData.sec   = Digs_To_Int (dt+12, 2);
  746.   ClockData.min      = Digs_To_Int (dt+10, 2);
  747.   ClockData.hour  = Digs_To_Int (dt+8, 2);
  748.   ClockData.mday  = Digs_To_Int (dt+6, 2);
  749.   ClockData.wday  = 0; /* is ignored by CheckDate() and Date2Amiga() */
  750.   ClockData.month = Digs_To_Int (dt+4, 2);
  751.   ClockData.year  = Digs_To_Int (dt, 4);
  752.  
  753.   if (CheckDate (&ClockData))
  754.     return Date2Amiga (&ClockData);
  755.   else
  756.     return 0;
  757. }
  758.  
  759. t_ulong Iso_Volume_Size (VOLUME *p_volume)
  760. {
  761.   return VOL(p_volume,pvd).space_size_m;
  762. }
  763.  
  764. t_ulong Iso_Block_Size (VOLUME *p_volume)
  765. {
  766.   return VOL(p_volume,pvd).block_size_m;
  767. }
  768.  
  769. void Iso_Volume_ID (VOLUME *p_volume, char *p_buffer, int p_buf_length)
  770. {
  771.   char *iso_name = VOL(p_volume,pvd).volume_id;
  772.   int iso_len;
  773.   int len;
  774.  
  775.   for (iso_len = 30; iso_len; iso_len--) {
  776.     if (iso_name[iso_len-1] != ' ')
  777.       break;
  778.   }
  779.  
  780.   len = (iso_len > p_buf_length-1) ? p_buf_length-1 : iso_len;
  781.   if (len > 0)
  782.     memcpy (p_buffer, iso_name, len);
  783.   p_buffer[len] = 0;
  784. }
  785.  
  786. t_ulong Iso_Location (CDROM_OBJ *p_object)
  787. {
  788.   return OBJ(p_object,dir)->extent_loc_m;
  789. }
  790.  
  791. t_ulong Iso_File_Length (CDROM_OBJ *p_obj)
  792. {
  793.   return OBJ(p_obj,dir)->data_length_m;
  794. }
  795.  
  796. t_handler g_iso_handler = {
  797.   Iso_Close_Vol_Info,
  798.   Iso_Open_Top_Level_Directory,
  799.   Iso_Open_Obj_In_Directory,
  800.   Iso_Find_Parent,
  801.   Iso_Close_Obj,
  802.   Iso_Read_From_File,
  803.   Iso_CDROM_Info,
  804.   Iso_Examine_Next,
  805.   Iso_Clone_Obj_Info,
  806.   Iso_Is_Top_Level_Object,
  807.   Iso_Same_Objects,
  808.   Iso_Creation_Date,
  809.   Iso_Volume_Size,
  810.   Iso_Volume_ID,
  811.   Iso_Location,
  812.   Iso_File_Length,
  813.   Iso_Block_Size
  814. };
  815.  
  816. t_handler g_rr_handler = {
  817.   Iso_Close_Vol_Info,
  818.   Iso_Open_Top_Level_Directory,
  819.   Iso_Open_Obj_In_Directory,
  820.   Iso_Find_Parent,
  821.   Iso_Close_Obj,
  822.   Iso_Read_From_File,
  823.   Iso_CDROM_Info,
  824.   Iso_Examine_Next,
  825.   Iso_Clone_Obj_Info,
  826.   Iso_Is_Top_Level_Object,
  827.   Iso_Same_Objects,
  828.   Iso_Creation_Date,
  829.   Iso_Volume_Size,
  830.   Iso_Volume_ID,
  831.   Iso_Location,
  832.   Iso_File_Length,
  833.   Iso_Block_Size
  834. };
  835.  
  836.